home *** CD-ROM | disk | FTP | other *** search
/ Aminet 50 / Aminet 50 (2002)(GTI - Schatztruhe)[!][Aug 2002].iso / Aminet / util / libs / ttrender.lha / ttrender-3.1 / Examples / TrueView / trueview.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-04-20  |  25.7 KB  |  843 lines

  1. #define __NOLIBBASE__
  2.  
  3. #include <proto/exec.h>
  4. #include <proto/dos.h>
  5. #include <proto/intuition.h>
  6. #include <proto/ttrender.h>
  7. #include <proto/utility.h>
  8. #include <proto/layers.h>
  9. #include <proto/graphics.h>
  10.  
  11. #define MARGIN_SIZE 2
  12.  
  13. extern struct Library *SysBase, *DOSBase;
  14.  
  15. struct Library *IntuitionBase = NULL,
  16.                *UtilityBase = NULL,
  17.                *TTRenderBase = NULL,
  18.                *GfxBase = NULL,
  19.                *LayersBase = NULL;
  20.  
  21. APTR mempool;
  22.  
  23. struct Parameters
  24.   {
  25.     STRPTR  file_name;
  26.     STRPTR  font_name;
  27.     ULONG  *font_size;
  28.   };
  29.  
  30. struct AppData
  31.   {
  32.     struct Window *win;
  33.     ULONG cypos;
  34.     ULONG total_height;
  35.     WORD l, t, r, b;        /* window showbox */
  36.     struct MinList token_list;
  37.     struct MinList line_list;
  38.     struct Parameters prm;
  39.     struct Gadget *last_clicked;
  40.     struct Gadget scroll;
  41.     struct PropInfo pinfo;
  42.     struct Image i1;
  43.     struct Image i2;
  44.     struct Screen *screen_lock;
  45.   };
  46.  
  47. /*--------------------------------------------------------------------------------------------------*/
  48.  
  49. void init_minlist(struct MinList *list)
  50.   {
  51.     list->mlh_Head = (struct MinNode*)&list->mlh_Tail;
  52.     list->mlh_Tail = NULL;
  53.     list->mlh_TailPred = (struct MinNode*)&list->mlh_Head;
  54.   }
  55.  
  56. /*==================================================================================================*/
  57. /* PARSER - generates a list of tokens from input file.                                             */
  58. /*==================================================================================================*/
  59.  
  60. struct TokenNode
  61.   {
  62.     struct TokenNode *next;
  63.     struct TokenNode *prev;
  64.     ULONG             ssize;
  65.     STRPTR            token;
  66.   };
  67.  
  68. /* states */
  69.  
  70. #define WRD 1
  71. #define SPC 2
  72. #define TAB 3
  73. #define NL1 4
  74. #define NL2 5
  75.  
  76. struct TokenNode *new_token_node(STRPTR token)
  77.   {
  78.     struct TokenNode *tn;
  79.  
  80.     if (tn = AllocPooled(mempool, sizeof(struct TokenNode)))
  81.       {
  82.         tn->ssize = strlen(token) + 1;
  83.         if (tn->token = AllocPooled(mempool, tn->ssize))
  84.           {
  85.             strcpy(tn->token, token);
  86.             return tn;
  87.           }
  88.         FreePooled(mempool, tn, sizeof(struct TokenNode));
  89.       }
  90.     return 0;
  91.   }
  92.  
  93. void emit_token(struct AppData *app, UBYTE *tok)
  94.   {
  95.     struct TokenNode *tn;
  96.  
  97.     if (tn = new_token_node(tok))
  98.       {
  99.         AddTail((struct List *)&app->token_list, (struct Node*)tn);
  100.       }
  101.   }
  102.  
  103. void emit_space(struct AppData *app)
  104.   {
  105.     struct TokenNode *tn;
  106.  
  107.     if (tn = new_token_node("<SPC>"))
  108.       {
  109.         AddTail((struct List *)&app->token_list, (struct Node*)tn);
  110.       }
  111.   }
  112.  
  113. void emit_tab(struct AppData *app)
  114.   {
  115.     struct TokenNode *tn;
  116.  
  117.     if (tn = new_token_node("<TAB>"))
  118.       {
  119.         AddTail((struct List *)&app->token_list, (struct Node*)tn);
  120.       }
  121.   }
  122.  
  123. void emit_lf(struct AppData *app)
  124.   {
  125.     struct TokenNode *tn;
  126.  
  127.     if (tn = new_token_node("<LF>"))
  128.       {
  129.         AddTail((struct List *)&app->token_list, (struct Node*)tn);
  130.       }
  131.   }
  132.  
  133. UBYTE get_next_char(BPTR in)
  134.   {
  135.     LONG c;
  136.  
  137.     c = FGetC(in);
  138.     if (c > 0) return (UBYTE)c;
  139.     else return 0;
  140.   }
  141.  
  142. void parse(struct AppData *app, BPTR in)
  143.   {
  144.     UBYTE c, *ptr, tok[80];
  145.     BYTE s = WRD;
  146.  
  147.     ptr = tok;
  148.  
  149.     while (c = get_next_char(in))
  150.       {
  151.         switch (s)
  152.           {
  153.             case WRD:
  154.               switch (c)
  155.                 {
  156.                   case 0x09: *ptr++ = 0x00; emit_token(app, tok); ptr = tok; s = TAB; break;
  157.                   case 0x0A: *ptr++ = 0x00; emit_token(app, tok); ptr = tok; s = NL1; break;
  158.                   case 0x0D:
  159.                   case 0x0F: *ptr++ = 0x00; emit_token(app, tok); ptr = tok; s = NL2; break;
  160.                   case 0x20: *ptr++ = 0x00; emit_token(app, tok); ptr = tok; s = SPC; break;
  161.                   default: *ptr++ = c;
  162.                 }
  163.               break;
  164.  
  165.             case SPC:
  166.               emit_space(app);
  167.               switch (c)
  168.                 {
  169.                   case 0x09: s = TAB; break;
  170.                   case 0x0A: s = NL1; break;
  171.                   case 0x0D:
  172.                   case 0x0F: s = NL2; break;
  173.                   case 0x20: break;
  174.                   default: *ptr++ = c; s = WRD;
  175.                 }
  176.               break;
  177.  
  178.             case TAB:
  179.               emit_tab(app);
  180.               switch (c)
  181.                 {
  182.                   case 0x09: break;
  183.                   case 0x0A: s = NL1; break;
  184.                   case 0x0D:
  185.                   case 0x0F: s = NL2; break;
  186.                   case 0x20: s = SPC; break;
  187.                   default: *ptr++ = c; s = WRD;
  188.                 }
  189.               break;
  190.  
  191.             case NL1:
  192.               switch (c)
  193.                 {
  194.                   case 0x09: emit_lf(app); s = TAB; break;
  195.                   case 0x0A: emit_lf(app); s = NL1; break;
  196.                   case 0x0D: s = NL2; break;
  197.                   case 0x0F: emit_lf(app); s = NL2; break;
  198.                   case 0x20: emit_lf(app); s = SPC; break;
  199.                   default: *ptr++ = c; emit_lf(app); s = WRD;
  200.                 }
  201.               break;
  202.  
  203.             case NL2:
  204.               emit_lf(app);
  205.               switch (c)
  206.                 {
  207.                   case 0x09: s = TAB; break;
  208.                   case 0x0A: s = NL1; break;
  209.                   case 0x0D:
  210.                   case 0x0F: s = NL2; break;
  211.                   case 0x20: s = SPC; break;
  212.                   default: *ptr++ = c; s = WRD;
  213.                 }
  214.               break;
  215.           }
  216.       }
  217.   }
  218.  
  219. /*==================================================================================================*/
  220. /* LF CLEANER - replaces single <LF> token with <SPC> token, and two adjacent <LF> tokens by single */
  221. /* <LF> token.                                                                                      */
  222. /*==================================================================================================*/
  223.  
  224. void lf_cleaner(struct MinList *token_list)
  225.   {
  226.     BOOL last_was_lf = FALSE;
  227.     struct TokenNode *tn, *new_tn, *prev_tn;
  228.  
  229.     tn = (struct TokenNode*)token_list->mlh_Head;
  230.  
  231.     for (tn = (struct TokenNode*)token_list->mlh_Head; tn->next; tn = tn->next)
  232.       {
  233.         prev_tn = tn->prev;
  234.  
  235.         if (strcmp(tn->token, "<LF>") == 0)
  236.           {
  237.             if (last_was_lf)
  238.               {
  239.                 Remove((struct Node*)prev_tn);
  240.                 last_was_lf = FALSE;
  241.               }
  242.             else last_was_lf = TRUE;
  243.           }
  244.         else  /* current token is not <LF> */
  245.           {
  246.             if (last_was_lf)  /* if last was <LF> replace it with <SPC> */
  247.               {
  248.                 if (new_tn = new_token_node("<SPC>"))
  249.                   {
  250.                     Insert((struct List*)token_list, (struct Node*)new_tn, (struct Node*)prev_tn);
  251.                     Remove((struct Node*)prev_tn);
  252.                   }
  253.               }
  254.             last_was_lf = FALSE;
  255.           }
  256.       }
  257.   }
  258.  
  259.  
  260. /*==================================================================================================*/
  261. /* LINE SPLITTER - generates a list of lines fitted to given width                                  */
  262. /*==================================================================================================*/
  263.  
  264. #define LINE_ALIGN_LEFT      0
  265. #define LINE_ALIGN_RIGHT     1
  266. #define LINE_ALIGN_CENTER    2
  267. #define LINE_ALIGN_JUSTIFY   3
  268.  
  269. struct TextLine
  270.   {
  271.     struct TextLine *next;
  272.     struct TextLine *prev;
  273.     ULONG pos_y;
  274.     ULONG tot_w;
  275.     BOOL last_line;             /* TRUE if the last line in paragraph */
  276.     struct MinList tokens;
  277.   };
  278.  
  279. struct TokenHandle
  280.   {
  281.     struct TokenHandle *next;
  282.     struct TokenHandle *prev;
  283.     struct TokenNode *token;
  284.     ULONG pos_x;
  285.   };
  286.  
  287. struct SplitterState
  288.   {
  289.     struct TextLine *ctl;             /* current text line */
  290.     ULONG cur_y;                      /* current vertical position in the document */
  291.     ULONG cur_w;                      /* current line width */
  292.     ULONG spc_w;                      /* space token width (cached for speed) */
  293.     ULONG lin_h;                      /* [current] height of current line */
  294.   };
  295.  
  296. /*--------------------------------------------------------------------------------------------------*/
  297.  
  298. struct TextLine *new_text_line(void)
  299.   {
  300.     struct TextLine *tl;
  301.  
  302.     if (tl = AllocPooled(mempool, sizeof(struct TextLine))) init_minlist(&tl->tokens);
  303.     tl->tot_w = 0;
  304.     tl->last_line = FALSE;
  305.     return tl;
  306.   }
  307.  
  308. /*--------------------------------------------------------------------------------------------------*/
  309.  
  310. void add_to_line(struct TextLine *line, struct TokenNode *tn, ULONG pos_x)
  311.   {
  312.     struct TokenHandle *th;
  313.  
  314.     if (th = AllocPooled(mempool, sizeof(struct TokenHandle)))
  315.       {
  316.         th->token = tn;
  317.         th->pos_x = pos_x;
  318.         AddTail((struct List*)&line->tokens, (struct Node*)th);
  319.       }
  320.   }
  321.  
  322. /*--------------------------------------------------------------------------------------------------*/
  323.  
  324. void cut_ending_spaces(struct MinList *line_list, ULONG space_width)
  325.   {
  326.     struct TextLine *txl;
  327.     struct TokenHandle *tkh_last;
  328.  
  329.     for(txl = (struct TextLine*)line_list->mlh_Head; txl->next; txl = txl->next)
  330.       {
  331.         tkh_last = (struct TokenHandle*)txl->tokens.mlh_TailPred;
  332.  
  333.         if (tkh_last != (struct TokenHandle*)&txl->tokens.mlh_Head)
  334.           {
  335.             if (strcmp(tkh_last->token->token, "<SPC>") == 0)
  336.               {
  337.                 Remove((struct Node*)tkh_last);
  338.                 FreePooled(mempool, tkh_last, sizeof(struct TokenHandle));
  339.                 txl->tot_w -= space_width;
  340.               }
  341.           }
  342.       }
  343.   }
  344.  
  345. /*--------------------------------------------------------------------------------------------------*/
  346.  
  347. void init_splitter(struct SplitterState *sps, struct MinList *line_list)
  348.   {
  349.     sps->ctl = NULL;
  350.     sps->cur_y = 0;
  351.     sps->cur_w = 0;
  352.     sps->spc_w = TT_StrWidth(" ");
  353.     sps->ctl = new_text_line();
  354.     AddTail((struct List*)line_list, (struct Node*)sps->ctl);
  355.     sps->ctl->pos_y = sps->cur_y;
  356.   }
  357.  
  358. /*--------------------------------------------------------------------------------------------------*/
  359.  
  360. void line_break(struct SplitterState *sps, struct MinList *line_list)
  361.   {
  362.     sps->cur_y += sps->lin_h;
  363.     sps->cur_w = 0;
  364.     sps->ctl = new_text_line();
  365.     AddTail((struct List*)line_list, (struct Node*)sps->ctl);
  366.     sps->ctl->pos_y = sps->cur_y;
  367.   }
  368.  
  369. /*--------------------------------------------------------------------------------------------------*/
  370.  
  371. void horiz_layout(struct MinList *line_list, ULONG width, ULONG mode)
  372.   {
  373.     struct TextLine *txl;
  374.  
  375.     if (mode == LINE_ALIGN_LEFT) return;  /* left layout is default */
  376.  
  377.     for (txl = (struct TextLine*)line_list->mlh_Head; txl->next; txl = txl->next)
  378.       {
  379.         switch (mode)
  380.           {
  381.             case LINE_ALIGN_RIGHT:
  382.               {
  383.                 ULONG freespace;
  384.                 struct TokenHandle *tkh;
  385.  
  386.                 freespace = width - txl->tot_w;
  387.  
  388.                 /* move all tokens right */
  389.  
  390.                 for (tkh = (struct TokenHandle*)txl->tokens.mlh_Head; tkh->next; tkh = tkh->next)
  391.                   {
  392.                     tkh->pos_x += freespace;
  393.                   }
  394.               }
  395.             break;
  396.  
  397.             case LINE_ALIGN_CENTER:
  398.               {
  399.                 ULONG freespace;
  400.                 struct TokenHandle *tkh;
  401.  
  402.                 freespace = width - txl->tot_w >> 1;
  403.  
  404.                 /* move all tokens right */
  405.  
  406.                 for (tkh = (struct TokenHandle*)txl->tokens.mlh_Head; tkh->next; tkh = tkh->next)
  407.                   {
  408.                     tkh->pos_x += freespace;
  409.                   }
  410.               }
  411.             break;
  412.  
  413.             case LINE_ALIGN_JUSTIFY:
  414.               {
  415.                 ULONG freespace, space_count = 0;
  416.                 ULONG spc_int, spc_frac, move_int = 0, move_frac = 0;
  417.                 struct TokenHandle *tkh;
  418.  
  419.                 /* the last line of the paragraph should be left (default) aligned */
  420.  
  421.                 if (txl->last_line) continue;
  422.  
  423.                 /* count spaces */
  424.  
  425.                 for (tkh = (struct TokenHandle*)txl->tokens.mlh_Head; tkh->next; tkh = tkh->next)
  426.                   {
  427.                     space_count++;
  428.                   }
  429.  
  430.                 if (space_count > 2)
  431.                   {
  432.                     space_count = space_count - 1 >> 1;
  433.                     freespace = width - txl->tot_w;
  434.                     if (freespace > 0)
  435.                       {
  436.                         spc_int = freespace / space_count;
  437.                         spc_frac = freespace % space_count;
  438.  
  439.                         /* list contains at least 2 tokens so we safely can start from the second */
  440.  
  441.                         for (tkh = ((struct TokenHandle*)txl->tokens.mlh_Head)->next; tkh->next; tkh = tkh->next)
  442.                           {
  443.                             if (strcmp(tkh->token->token, "<SPC>") != 0)
  444.                               {
  445.                                 move_int += spc_int;
  446.                                 move_frac += spc_frac;
  447.                                 if (move_frac >= space_count)
  448.                                   {
  449.                                     move_frac -= space_count;
  450.                                     move_int++;
  451.                                   }
  452.                               }
  453.                             tkh->pos_x += move_int;
  454.                           }
  455.                       }
  456.                   }
  457.               }
  458.             break;
  459.           }
  460.       }
  461.   }
  462.  
  463. /*--------------------------------------------------------------------------------------------------*/
  464.  
  465. void line_splitter(struct AppData *app)
  466.   {
  467.     struct SplitterState sps;
  468.     struct TokenNode *tn;
  469.     ULONG tok_w, width = app->r - app->l + 1, line_height = *app->prm.font_size;
  470.  
  471.  
  472.     init_minlist(&app->line_list);
  473.     init_splitter(&sps, &app->line_list);
  474.     sps.lin_h = line_height;
  475.  
  476.     for (tn = (struct TokenNode*)app->token_list.mlh_Head; tn->next; tn = tn->next)
  477.       {
  478.         if (strcmp(tn->token, "<SPC>") == 0)
  479.           {
  480.             if (sps.cur_w + sps.spc_w > width) line_break(&sps, &app->line_list);
  481.             else
  482.               {
  483.                 add_to_line(sps.ctl, tn, sps.cur_w);
  484.                 sps.cur_w += sps.spc_w;
  485.                 sps.ctl->tot_w = sps.cur_w;
  486.               }
  487.           }
  488.         else if (strcmp(tn->token, "<LF>") == 0)
  489.           {
  490.             sps.ctl->last_line = TRUE;
  491.             line_break(&sps, &app->line_list);
  492.           }
  493.         else
  494.           {
  495.             tok_w = TT_StrWidth(tn->token);
  496.             if (sps.cur_w == 0 && tok_w > width)
  497.               {
  498.                 add_to_line(sps.ctl, tn, sps.cur_w);
  499.                 sps.ctl->tot_w = width;
  500.                 line_break(&sps, &app->line_list);
  501.               }
  502.             else if (sps.cur_w + tok_w > width)
  503.               {
  504.                 line_break(&sps, &app->line_list);
  505.                 add_to_line(sps.ctl, tn, sps.cur_w);
  506.                 sps.cur_w += tok_w;
  507.                 sps.ctl->tot_w = sps.cur_w;
  508.               }
  509.             else
  510.               {
  511.                 add_to_line(sps.ctl, tn, sps.cur_w);
  512.                 sps.cur_w += tok_w;
  513.                 sps.ctl->tot_w = sps.cur_w;
  514.               }
  515.           }
  516.       }
  517.     app->total_height = sps.cur_y + sps.lin_h;
  518.     cut_ending_spaces(&app->line_list, sps.spc_w);
  519.     horiz_layout(&app->line_list, width, LINE_ALIGN_LEFT);
  520.   }
  521.  
  522. /*==================================================================================================*/
  523.  
  524. BOOL open_libs(void)
  525.   {
  526.     if (!(GfxBase = OpenLibrary("graphics.library", 39))) return FALSE;
  527.     if (!(LayersBase = OpenLibrary("layers.library", 38))) return FALSE;
  528.     if (!(IntuitionBase = OpenLibrary("intuition.library", 39))) return FALSE;
  529.     if (!(UtilityBase = OpenLibrary("utility.library", 39))) return FALSE;
  530.     if (!(TTRenderBase = OpenLibrary("ttrender.library", 2))) return FALSE;
  531.     return TRUE;
  532.   }
  533.  
  534. /*--------------------------------------------------------------------------------------------------*/
  535.  
  536. void close_libs(void)
  537.   {
  538.     if (TTRenderBase) CloseLibrary(TTRenderBase);
  539.     if (UtilityBase) CloseLibrary(UtilityBase);
  540.     if (IntuitionBase) CloseLibrary(IntuitionBase);
  541.     if (LayersBase) CloseLibrary(LayersBase);
  542.     if (GfxBase) CloseLibrary(GfxBase);
  543.   }
  544.  
  545. /*--------------------------------------------------------------------------------------------------*/
  546.  
  547. void render_text(struct AppData *app, LONG from, LONG to)
  548.   {
  549.     struct TextLine *txl;
  550.     struct TokenHandle *tkh;
  551.     struct Region *rgn, *old_rgn;
  552.     struct Rectangle rect;
  553.     ULONG spc_w, ascend;
  554.  
  555.     TT_SetModesTags(
  556.       TTA_Window, (ULONG)app->win,
  557.       TTA_Antialias, FALSE,
  558.       TAG_END);
  559.  
  560.     TT_GetFontAttrsTags(
  561.       TTFA_Ascender, (ULONG)&ascend,
  562.       TAG_END);
  563.  
  564.     spc_w = TT_StrWidth("ยท");
  565.  
  566.     if (rgn = NewRegion())
  567.       {
  568.         rect.MinX = app->l;
  569.         rect.MinY = from + app->t;
  570.         rect.MaxX = app->r;
  571.         rect.MaxY = to + app->t;
  572.         if (OrRectRegion(rgn, &rect))
  573.           {
  574.             old_rgn = InstallClipRegion(app->win->WLayer, rgn);
  575.             for(txl = (struct TextLine*)app->line_list.mlh_Head; txl->next; txl = txl->next)
  576.               {
  577.                 if ((txl->pos_y + *app->prm.font_size > from + app->cypos) && (txl->pos_y <= to + app->cypos))
  578.                   {
  579.                     for(tkh = (struct TokenHandle*)txl->tokens.mlh_Head; tkh->next; tkh = tkh->next)
  580.                       {
  581.                         if (strcmp(tkh->token->token, "<SPC>") == 0);
  582.                         else
  583.                           {
  584.                             Move(app->win->RPort, tkh->pos_x + app->l,
  585.                              txl->pos_y + ascend + app->t - app->cypos);
  586.                             TT_PutStr(tkh->token->token);
  587.                           }
  588.                       }
  589.                   }
  590.               }
  591.             InstallClipRegion(app->win->WLayer, old_rgn);
  592.           }
  593.         DisposeRegion(rgn);
  594.      }
  595.   }
  596.  
  597. /*--------------------------------------------------------------------------------------------------*/
  598.  
  599. void move_text(struct AppData *app, LONG newpos)
  600.   {
  601.     LONG delta = newpos - app->cypos;
  602.  
  603.     app->cypos = newpos;
  604.  
  605.     if (delta > 0)
  606.       {
  607.         if (delta < app->b - app->t)
  608.           {
  609.             ScrollRasterBF(app->win->RPort, 0, delta, app->l, app->t, app->r, app->b);
  610.             render_text(app, app->b - app->t - delta + 1, app->b - app->t);
  611.           }
  612.         else
  613.           {
  614.             EraseRect(app->win->RPort, app->l, app->t, app->r, app->b);
  615.             render_text(app, 0, app->b - app->t);
  616.           }
  617.       }
  618.     else if (delta < 0)
  619.       {
  620.         if (-delta < app->b - app->t)
  621.           {
  622.             ScrollRasterBF(app->win->RPort, 0, delta, app->l, app->t, app->r, app->b);
  623.             render_text(app, 0, -delta + 1);
  624.           }
  625.         else
  626.           {
  627.             EraseRect(app->win->RPort, app->l, app->t, app->r, app->b);
  628.             render_text(app, 0, app->b - app->t);
  629.           }
  630.       }
  631.   }
  632.  
  633. /*--------------------------------------------------------------------------------------------------*/
  634.  
  635. inline void update_box_sizes(struct AppData *app)
  636.   {
  637.     app->l = app->win->BorderLeft + MARGIN_SIZE;
  638.     app->t = app->win->BorderTop + MARGIN_SIZE;
  639.     app->r = app->win->Width - app->win->BorderRight - MARGIN_SIZE - 1;
  640.     app->b = app->win->Height - app->win->BorderBottom - MARGIN_SIZE - 1;
  641.   }
  642.  
  643. /*--------------------------------------------------------------------------------------------------*/
  644.  
  645. void update_scroller(struct AppData *app)
  646.   {
  647.     UWORD vbody;
  648.     UWORD vpot;
  649.     UWORD visible;
  650.  
  651.     visible = app->b - app->t + 1;
  652.  
  653.     if (app->total_height <= visible)
  654.       {
  655.         vpot = 0;
  656.         vbody = 65535;
  657.       }
  658.     else
  659.       {
  660.         vpot = ((app->cypos << 16) - app->cypos) / (app->total_height - visible);
  661.         vbody = ((visible << 16) - visible) / app->total_height;
  662.       }
  663.  
  664.     NewModifyProp(&app->scroll, app->win, NULL, AUTOKNOB | FREEVERT | PROPBORDERLESS | PROPNEWLOOK,
  665.      0, vpot, 0, vbody, 1);
  666.   }
  667.  
  668. /*--------------------------------------------------------------------------------------------------*/
  669.  
  670. void main_loop(struct AppData *app)
  671.   {
  672.     ULONG signals, portmask;
  673.     BOOL running = TRUE;
  674.  
  675.     portmask = 1 << app->win->UserPort->mp_SigBit;
  676.  
  677.     while (running)
  678.       {
  679.         signals = Wait(SIGBREAKF_CTRL_C | portmask);
  680.         if (signals & SIGBREAKF_CTRL_C) running = FALSE;
  681.         if (signals & portmask)
  682.           {
  683.             struct IntuiMessage *imsg;
  684.             ULONG msg_class;
  685.             APTR msg_iaddr;
  686.  
  687.             while (imsg = (struct IntuiMessage*)GetMsg(app->win->UserPort))
  688.               {
  689.                 msg_class = imsg->Class;
  690.                 msg_iaddr = imsg->IAddress;
  691.                 ReplyMsg((struct Message*)imsg);
  692.                 switch (msg_class)
  693.                   {
  694.                     case IDCMP_CLOSEWINDOW:
  695.                       running = FALSE;
  696.                     break;
  697.  
  698.                     case IDCMP_NEWSIZE:
  699.                       update_box_sizes(app);
  700.                       EraseRect(app->win->RPort, app->win->BorderLeft, app->win->BorderTop,
  701.                        app->win->Width - app->win->BorderRight - 1,
  702.                        app->win->Height - app->win->BorderBottom - 1);
  703.                       line_splitter(app);
  704.                       render_text(app, 0, app->b - app->t);
  705.                       update_scroller(app);
  706.                     break;
  707.  
  708.                     case IDCMP_GADGETDOWN:
  709.                       app->last_clicked = (struct Gadget*)msg_iaddr;
  710.                     break;
  711.  
  712.                     case IDCMP_GADGETUP:
  713.                       if (app->last_clicked == &app->scroll)
  714.                         {
  715.                           ULONG newpos;
  716.  
  717.                           newpos = app->pinfo.VertPot * (app->total_height - (app->b - app->t + 1)) / 65535;
  718.                           if (newpos != app->cypos)
  719.                             {
  720.                               move_text(app, newpos);
  721.                             }
  722.                         }
  723.                       app->last_clicked = NULL;
  724.                     break;
  725.  
  726.                     case IDCMP_MOUSEMOVE:
  727.                       if (app->last_clicked == &app->scroll)
  728.                         {
  729.                           ULONG newpos;
  730.  
  731.                           newpos = app->pinfo.VertPot * (app->total_height - (app->b - app->t + 1)) / 65535;
  732.                           if (newpos != app->cypos)
  733.                             {
  734.                               move_text(app, newpos);
  735.                             }
  736.                         }
  737.                     break;
  738.                   }
  739.               }
  740.           }
  741.       }
  742.   }
  743.  
  744.  
  745. void setup_scroller(struct AppData *app)
  746.   {
  747.     app->scroll.NextGadget = NULL;
  748.     app->scroll.LeftEdge = 5 - app->win->BorderRight;
  749.     app->scroll.TopEdge = app->win->BorderTop + 3;
  750.     app->scroll.Width = app->win->BorderRight - 8;
  751.     app->scroll.Height = -60;
  752.     app->scroll.Flags = GFLG_GADGHNONE | GFLG_RELRIGHT | GFLG_RELHEIGHT;
  753.     app->scroll.Activation = GACT_IMMEDIATE | GACT_RELVERIFY | GACT_RIGHTBORDER | GACT_FOLLOWMOUSE;
  754.     app->scroll.GadgetType = GTYP_PROPGADGET;
  755.     app->scroll.GadgetRender = &app->i1;
  756.     app->scroll.SelectRender = &app->i2;
  757.     app->scroll.GadgetText = NULL;
  758.     app->scroll.SpecialInfo = &app->pinfo;
  759.  
  760.     app->pinfo.Flags = AUTOKNOB | FREEVERT | PROPBORDERLESS | PROPNEWLOOK;
  761.     app->pinfo.HorizPot = 0;
  762.     app->pinfo.VertPot = 0;
  763.     app->pinfo.HorizBody = 65535;
  764.     app->pinfo.VertBody = 65535;
  765.  
  766.     AddGadget(app->win, &app->scroll, ~0);
  767.     RefreshGadgets(&app->scroll, app->win, NULL);
  768.   }
  769.  
  770. LONG Main (void)
  771.   {
  772.     BPTR in;
  773.     Class *rect, *text;
  774.     WORD i;
  775.     struct AppData app;
  776.     struct RDArgs *args;
  777.     ULONG default_size = 14;
  778.  
  779.     app.cypos = 0;
  780.     app.prm.file_name = "";
  781.     app.prm.font_name = "";
  782.     app.prm.font_size = &default_size;
  783.  
  784.     if (open_libs())
  785.       {
  786.         if (args = ReadArgs("FILE/A,FONTNAME=-f/K/A,FONTSIZE=-s/K/N", (LONG*)&app.prm, NULL))
  787.           {
  788.             if (mempool = CreatePool(MEMF_ANY, 4096, 4096))
  789.               {
  790.                 init_minlist(&app.token_list);
  791.  
  792.                 if (app.screen_lock = LockPubScreen(NULL))
  793.                   {
  794.                     if (app.win = OpenWindowTags(NULL,
  795.                       WA_Width, 600,
  796.                       WA_Height, 350,
  797.                       WA_DragBar, TRUE,
  798.                       WA_DepthGadget, TRUE,
  799.                       WA_CloseGadget, TRUE,
  800.                       WA_SizeGadget, TRUE,
  801.                       WA_MinWidth, 200,
  802.                       WA_MinHeight, 100,
  803.                       WA_MaxWidth, ~0,
  804.                       WA_MaxHeight, ~0,
  805. //                      WA_Gadgets, (ULONG)&app.scroll,
  806.                       WA_IDCMP, IDCMP_CLOSEWINDOW | IDCMP_NEWSIZE | IDCMP_GADGETDOWN | IDCMP_GADGETUP |
  807.                         IDCMP_MOUSEMOVE,
  808.                       WA_Title, (ULONG)"TrueView",
  809.                       TAG_END))
  810.                       {
  811.                         setup_scroller(&app);
  812.                         if (in = Open(app.prm.file_name, MODE_OLDFILE))
  813.                           {
  814.                             parse(&app, in);
  815.                             Close(in);
  816.                             //lf_cleaner(&app.token_list);
  817.                             if (TT_SetFont(app.prm.font_name, *app.prm.font_size))
  818.                               {
  819.                                 update_box_sizes(&app);
  820.                                 line_splitter(&app);
  821.                                 SetAPen(app.win->RPort, 1);
  822.                                 SetDrMd(app.win->RPort, JAM1);
  823.                                 render_text(&app, 0, app.b - app.t);
  824.                                 update_scroller(&app);
  825.                                 main_loop(&app);
  826.                               }
  827.                             else PutStr("Failed to open font.\n");
  828.                           }
  829.                         else PrintFault(IoErr(), "TrueView");
  830.                         CloseWindow(app.win);
  831.                       }
  832.                     UnlockPubScreen(NULL, app.screen_lock);
  833.                   }
  834.                 DeletePool(mempool);
  835.               }
  836.             FreeArgs(args);
  837.           }
  838.         else PrintFault(IoErr(), "TrueView");
  839.       }
  840.     close_libs();
  841.     return 0;
  842.   }
  843.